﻿using System;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.Library.Data.Imaging;

namespace RayDen.Library.Components.Surface.Spectral
{
    [Serializable]
    public class MatteMaterial : SpectralBrdf
    {
        public override BrdfType Type
        {
            get { return BrdfType.Diffuse; }
        }

        public MatteMaterial(RgbSpectrum col)
        {
            Kd = ColorFactory.CreateRegularSpd(ref col, SpectrumType.Reflectance);
        }
        public MatteMaterial(RegularSPD col)
        {
            Kd = col;
        }

        public override bool IsDiffuse() { return true; }
        public override bool IsSpecular() { return false; }

        public override void F(ref Vector wo, ref Vector wi, ref Normal N, float lambda, out float fs)
        {
            fs = Kd.Sample(lambda) * MathLab.INVPI;
        }

        protected void EvalParams(ref SurfaceTextureData surfaceData, float lambda)
        {
            Kd = ColorFactory.CreateRegularSpd(ref surfaceData.Diffuse, SpectrumType.Reflectance);
        }

        public override void Sample_f(ref Vector wo, ref Normal geoNormal, ref Normal shadeN, float lambda, ref SurfaceTextureData surfaceData, float u0, float u1, float u2, out BsdfSampleData result)
        {
            EvalParams(ref surfaceData, lambda);
            Vector dir =
                MC.CosineSampleHemisphere(u0, u1);
            result = new BsdfSampleData { Pdf = dir.z*MathLab.INVPI, Type = BrdfType.Diffuse}; // TODO Lambda weight
            Vector v1, v2;
            Normal n = geoNormal;
            Vector.CoordinateSystem(ref n, out v1, out v2);
            
            dir = new Vector(
                v1.x * dir.x + v2.x * dir.y + n.x * dir.z,
                v1.y * dir.x + v2.y * dir.y + n.y * dir.z,
                v1.z * dir.x + v2.z * dir.y + n.z * dir.z);

            var wi = dir;

            float dp = (Normal.Dot(ref shadeN, ref wi));
            // Using 0.01 instead of 0.0 to cut down fireflies
            if (dp <= 0.0001f)
            {
                result.Pdf = 0f;
                result.F = new RgbSpectrum();
                result.Lambda = 0f;
            }
            else
            {
                result.Pdf /= dp;
                result.F = surfaceData.Diffuse * MathLab.INVPI;
                result.Lambda = Kd.Sample(lambda)*MathLab.INVPI;
            }
            result.Wi = wi;
        }


        private SpectralDistribution Kd;
    };
}